#include <iostream>
#include <stack>

#include "../include/BoneManager.h"
#include "../include/BoneTreeCtrl.h"
#include "../include/TreeItemDataBoneId.h"

BEGIN_EVENT_TABLE(BoneTreeCtrl, wxTreeCtrl)
    EVT_TREE_SEL_CHANGED (wxID_ANY, BoneTreeCtrl::itemSelected)
END_EVENT_TABLE()

BoneTreeCtrl::BoneTreeCtrl(wxWindow* parent,
                           wxWindowID id,
                           const wxPoint& pos,
                           const wxSize& size,
                           long style,
                           const wxValidator& validator,
                           const wxString& name)
:wxTreeCtrl(parent, id, pos, size, style, validator, name)
{
    boneManager = NULL;
    this->rootBone = NULL;
    this->selectionByMethodCall = false;
}

BoneTreeCtrl::~BoneTreeCtrl() {}

void BoneTreeCtrl::clear()
{
    // Clearing the tree
    if (rootBone)
        DeleteAllItems();
    rootBone = NULL;
}

void BoneTreeCtrl::itemSelected(wxTreeEvent& evt )
{
    // selection made by method
    // update only in tree, not in bones
    if (this->selectionByMethodCall)
        return;

    // update invoke by mouse click on tree
    // id of bone that will be selected

    unsigned int boneId = dynamic_cast< TreeItemDataBoneId* >( GetItemData(evt.GetItem()) )->boneId;

    // bone to select
    Bone *bone = boneManager->findBoneById(boneId);
    if (!bone)
    {
        std::cerr << "Searching bone failed, invoke from BoneTreeCtrl::itemSelected" << std::endl;
        return;
    }

    boneManager->selectBone(bone, Bone::END);
    //boneManager->updateBoneInfo();
    boneManager->Refresh();

    this->selectionByMethodCall = false;
}

void BoneTreeCtrl::setBoneManager(BoneManager* boneManager)
{
    this->boneManager = boneManager;
}


void BoneTreeCtrl::rebuild(Bone* rootBone)
{
    if (!boneManager || !rootBone)
    {
        std::cerr << "There are no boneManager or rootBone is wrong";
        return;
    }

    this -> rootBone = rootBone;

    // Clearing the tree
    DeleteAllItems();

    // Rebuilding tree
    std::list< Bone*> bones;
    std::list< wxTreeItemId> parents;

    bones.push_back(rootBone);
    parents.push_back ( AddRoot(rootBone->getName(), -1, -1, new TreeItemDataBoneId(rootBone->getBoneId()) ) );

    std::list< Bone* >::iterator listIt, childenIt;
    std::list< wxTreeItemId>::iterator parentsIt = parents.begin();

    for ( listIt = bones.begin(); listIt != bones.end(); ++listIt)
    {
        for ( childenIt = ( (*listIt)->getChildren() ).begin(); childenIt != ( (*listIt)->getChildren() ).end(); ++childenIt)
        {
            bones.push_back( (*childenIt) );
            parents.push_back ( AppendItem(*parentsIt, (*childenIt)->getName(), -1, -1, new TreeItemDataBoneId( (*childenIt)->getBoneId() )) );
        }
        ++parentsIt;
    }

    ExpandAll();
}

void BoneTreeCtrl::updateSelection()
{
    if(!rootBone)
    {
        std::cerr << "There are no bones";
        return;
    }

    // check if rootBone is selected
    if (rootBone->getSelectedJoint() != Bone::NON)
    {
        this->selectionByMethodCall = true;
            SelectItem(GetRootItem());
        this->selectionByMethodCall = false;
        return;
    }

    Bone* selectedBoneInSceleton = boneManager->getSelectedBone();
    if (selectedBoneInSceleton)
    {
        // searching bone in tree
        wxTreeItemId  id = findBone( selectedBoneInSceleton );
        if ( !id.IsOk())
        {
            std::cerr << "Bone not found";
            return;
        }
        this->selectionByMethodCall = true;
            SelectItem(id);
        this->selectionByMethodCall = false;
    }
}


void BoneTreeCtrl::selectBone(Bone* bone)
{

}

wxTreeItemId BoneTreeCtrl::findBone(Bone* bone)
{
	std::stack<wxTreeItemId> items;
	if (GetRootItem().IsOk())
		items.push(GetRootItem());

	while (!items.empty())
	{
		wxTreeItemId next = items.top();
		items.pop();

		if (next != GetRootItem() && dynamic_cast<TreeItemDataBoneId*>(GetItemData(next))->boneId == bone->getBoneId())
			return next;

		wxTreeItemIdValue cookie;
		wxTreeItemId nextChild = GetFirstChild(next, cookie);
		while (nextChild.IsOk())
		{
			items.push(nextChild);
			nextChild = GetNextSibling(nextChild);
		}
	}

	return wxTreeItemId();
}

